package cn.keniykey.mc.viewlibrary.reflection;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;

import javax.annotation.Nullable;

public final class SearchReflectionField implements Cloneable{
	private EReflectionPermission permission;
	private String name,name_prefix,name_suffix;
	private Class<?>[] classes;
	private byte property_static,property_final;
	
	private final int fields_index;
	
	public SearchReflectionField(int index) {
		this.fields_index = index;
	}
	public SearchReflectionField() {
		this.fields_index = 0;
	}
	
	public SearchReflectionField setName(@Nullable String name1) {
		this.name = name1;
		return this;
	}
	public SearchReflectionField setNamePrefix(@Nullable String prefix) {
		this.name_prefix = prefix;
		return this;
	}
	public SearchReflectionField setNameSuffix(@Nullable String suffix) {
		this.name_suffix = suffix;
		return this;
	}
	public SearchReflectionField setClass(Class<?>...classes1) {
		this.classes = classes1;
		return this;
	}
	public SearchReflectionField setPermission(@Nullable EReflectionPermission per) {
		this.permission = per;
		return this;
	}
	public SearchReflectionField setStatic(boolean state) {
		this.property_static = (byte)(state ? 2 : 1);
		return this;
	}
	public SearchReflectionField setFinal(boolean state) {
		this.property_final = (byte)(state ? 2 : 1);
		return this;
	}
	ArrayList<Field> findFields(final Class<?> clazz) {
		final HashSet<Field> hashset_fields = new HashSet<>();
		Collections.addAll(hashset_fields, clazz.getFields());
		Collections.addAll(hashset_fields, clazz.getDeclaredFields());
		final LinkedList<Field> fields = new LinkedList<>(hashset_fields);
		hashset_fields.clear();
		final Iterator<Field> it = fields.iterator();
		fields_while : while(it.hasNext()) {
			final Field field = it.next();
			if(this.name != null && !field.getName().equals(this.name)) {
				it.remove();
				continue;
			}
			if(this.name_prefix != null && !field.getName().startsWith(this.name_prefix)) {
				it.remove();
				continue;
			}
			if(this.name_suffix != null && !field.getName().endsWith(this.name_suffix)) {
				it.remove();
				continue;
			}
			final int modifiers = field.getModifiers();
			if(this.permission != null && !this.permission.isModifiers(modifiers)) {
				it.remove();
				continue;
			}
			if(this.property_static > 0) {
				if(Modifier.isStatic(modifiers) != (this.property_static == 2)) {
					it.remove();
					continue;
				}
			}
			if(this.property_final > 0) {
				if(Modifier.isFinal(modifiers) != (this.property_final == 2)) {
					it.remove();
					continue;
				}
			}
			if(this.classes != null && this.classes.length > 0) {
				final Object obj = ReflectionGenericClass.getParameterClasses(clazz);
				if(obj instanceof Class) {
					if(this.classes.length != 1 || !obj.equals(this.classes[0])) {
						it.remove();
						continue;
					}
				}else if(obj instanceof LinkedList) {
					final LinkedList<?> linkeds = (LinkedList<?>) obj;
					if(this.classes.length != linkeds.size()) {
						it.remove();
						continue;
					}
					int index = 0;
					for(final Object forobj : linkeds) {
						if(!forobj.equals(this.classes[index])) {
							it.remove();
							continue fields_while;
						}
						index++;
					}
				}else {
					throw new RuntimeException("get parameters return unknown type(获取参数返回未知类型)");
				}
			}
		}
		try {
			return new ArrayList<>(fields);
		}finally {
			fields.clear();
		}
	}
	Field findField(final Class<?> clazz) {
		final ArrayList<Field> fields = this.findFields(clazz);
		if(fields.isEmpty()) throw new RuntimeException("can not find the field(NoSuchFieldException)(找不到指定Field参数): ");
		try {
			if(this.fields_index >= fields.size()) throw new RuntimeException("the such field index out of found fields amount"
					+ "(IndexOutOfBoundsException)(需求参数索引位置超出目前搜到的上限): " + this.fields_index + "/" + fields.size());
			return fields.get(this.fields_index);
		}finally {
			fields.clear();
		}
	}
    @Override
    public String toString() {
        final StringBuilder b = new StringBuilder(this.getClass().getSimpleName() + "{");
        if (this.name != null) {
            b.append("[name:").append(this.name).append("]");
        }
        if (this.name_prefix != null) {
            b.append("[prefix:").append(this.name_prefix).append("]");
        }
        if (this.name_suffix != null) {
            b.append("[suffix:").append(this.name_suffix).append("]");
        }
        if(this.classes != null && this.classes.length > 0) {
        	b.append("[classes:").append(Arrays.toString(this.classes)).append("]");
        }
        if(this.permission != null) {
        	b.append("[permission:").append(this.permission.toString()).append("]");
        }
        if(this.property_static != 0) {
        	b.append("[static:").append(this.property_static==2).append("]");
        }
        if(this.property_final != 0) {
        	b.append("[final:").append(this.property_final==2).append("]");
        }
        b.append("[index:").append(this.fields_index).append("]");
        b.append("}");
        return b.toString();
    }
    @Override
    public SearchReflectionField clone(){
    	final SearchReflectionField search = new SearchReflectionField(this.fields_index);
    	search.name = this.name;
    	search.name_prefix = this.name_prefix;
    	search.name_suffix = this.name_suffix;
    	search.permission = this.permission;
    	search.property_final = this.property_final;
    	search.property_static = this.property_static;
    	if(this.classes != null && this.classes.length > 0) {
//    		search.classes = new Class[this.classes.length];
//    		for(int index = 0; index < this.classes.length; index++) search.classes[index] = this.classes[index];
    		search.classes = Arrays.copyOf(this.classes, this.classes.length);
    	}
    	return search;
    }
}